

#include "../luaMPI.h"
#include <boost/mpi.hpp>
#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/complex.hpp>
#include <iostream>

namespace mpi{
	namespace world{
		boost::mpi::communicator world;
		int rank(void)
		{
			return world.rank();
		}
		int size(void)
		{
			return world.size();
		}
		void barrier(void)
		{
			world.barrier();
		}

		template<class T>
		void broadcast(T& val, int root){
			boost::mpi::broadcast(world,val,root);
		}
		template<class T>
		void send(int dest, int tag, const T& value)
		{
			world.send(dest,tag,value);
		}
		template<class T>
		void recv(int source, int tag, T& value)
		{
			world.recv(source,tag,value);
		}
		template<class T>
		boost::mpi::request isend(int dest, int tag, const T& value)
		{
			return world.isend(dest,tag,value);
		}
		template<class T>
		boost::mpi::request irecv(int source, int tag, T& value)
		{
			return world.irecv(source,tag,value);
		}


		//template void broadcast<int>(int, int);
		//template void broadcast<double>(double, int);
		template void broadcast<std::vector<double> >(std::vector<double>&, int);
		template void broadcast<std::vector<std::complex<double>> >(std::vector<std::complex<double>>&, int);
		//template void broadcast<std::string>(std::string, int);

		//template void send<int>(int dest, int tag, const int& value);
		//template void send<double>(int dest, int tag, const double& value);
		template void send<std::vector<double> >(int dest, int tag, const std::vector<double>& value);
		template void send<std::vector<std::complex<double> > >(int dest, int tag, const std::vector<std::complex<double>>& value);

		//template void send<std::string>(int dest, int tag, const std::string& value);

		//template void recv<int>(int dest, int tag, int& value);
		//template void recv<double>(int dest, int tag, double& value);
		template void recv<std::vector<double> >(int dest, int tag, std::vector<double>& value);
		template void recv<std::vector<std::complex<double> > >(int dest, int tag, std::vector<std::complex<double>>& value);
		//template void recv<std::string>(int dest, int tag, std::string& value);

		//template boost::mpi::request  isend<int>(int dest, int tag, const int& value);
		//template boost::mpi::request  isend<double>(int dest, int tag, const double& value);
		template boost::mpi::request  isend<std::vector<double> >(int dest, int tag, const std::vector<double>& value);
		template boost::mpi::request  isend<std::vector<std::complex<double> > >(int dest, int tag, const std::vector<std::complex<double>>& value);
		template boost::mpi::request  isend<std::vector<std::string > >(int dest, int tag, const std::vector<std::string>& value);
		//template boost::mpi::request  isend<std::string>(int dest, int tag, const std::string& value);

		//template boost::mpi::request  irecv<int>(int dest, int tag, int& value);
		//template boost::mpi::request  irecv<double>(int dest, int tag, double& value);
		template boost::mpi::request  irecv<std::vector<double> >(int dest, int tag, std::vector<double>& value);
		template boost::mpi::request  irecv<std::vector<std::complex<double> > >(int dest, int tag, std::vector<std::complex<double>>& value);
		template boost::mpi::request  irecv<std::vector<std::string > >(int dest, int tag, std::vector<std::string>& value);
		//template boost::mpi::request  irecv<std::string>(int dest, int tag, std::string& value);
	};
	void wait_all( std::list<boost::mpi::request>& reqs )
	{
	    boost::mpi::wait_all(reqs.begin(),reqs.end());
	}
};


